package com.biye.api.tool.security.config;

import com.biye.api.tool.security.filter.JwtAuthenticationFilter;
import com.biye.api.tool.security.handler.MyAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAccessDeniedHandler myAccessDenied;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 停掉同源保护策略，即俩服务端口号或IP不统一。即允许跨域，需要在当前配置类中声明corsConfigurationSource方法
        http.cors().and();

        // 由于使用的是JWT，我们这里不需要csrf
        http.csrf().disable();

        // 基于token，所以不需要session
        http.sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .sessionFixation().none();

        // 所有用户可以访问"/resources"目录下的资源以及访问favicon.ico
        http.authorizeRequests().antMatchers("/resources/**", "/**/favicon.ico").permitAll()
        // 访问其他的路径需要判断权限
        .anyRequest().access("@rbacService.hasPermission(request, authentication)");

        // 禁用缓存
        http.headers().cacheControl();

        // 添加JWT filter，在所有请求之前
        http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

        // 添加自定义认证失败403处理@rbacService.hasPermission() == false
        // http.exceptionHandling().accessDeniedPage("/page/403.html");  // 页面版（Method one）
        http.exceptionHandling().accessDeniedHandler(myAccessDenied);  // // 前后端分离版（Method two）
    }


    // JWT filter // 可以在类中配置放行接口
    @Bean
    public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationFilter();
    }

    // 对跨域的处理
    @Bean
    Object corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
//        configuration.setAllowedOrigins(Arrays.asList("http://192.168.170.160:8080", "http://173.26.85.41:36626"));
        configuration.addAllowedOrigin("*");//修改为添加而不是设置，* 最好改为实际的需要，我这是非生产配置，所以粗暴了一点
//        configuration.setAllowedMethods(Arrays.asList("GET", "PUT", "POST", "DELETE", "OPTION"));
        configuration.addAllowedMethod("*");//修改为添加而不是设置
        configuration.addAllowedHeader("*");//这里很重要，起码需要允许 Access-Control-Allow-Origin
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    // 静态资源
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/index.html")
                .antMatchers("/error");
    }

}